#ifndef MCURSORSVIEW_H
#define MCURSORSVIEW_H

#include <QObject>
#include <KXMLGUIClient>
#include <KTextEditor/Cursor>
#include <KTextEditor/Range>
#include <KTextEditor/MovingCursor>
#include <list>
#include <memory>
#include <QColor>
#include <QTextFormat>

namespace KTextEditor
{
class MovingRange;
class Document;
class MovingInterface;
}


class MCursorsView : public QObject, public KXMLGUIClient
{
	Q_OBJECT
public:
	explicit MCursorsView(KTextEditor::View *view = 0);
	~MCursorsView();

	void setCursorColor(const QColor& color);
	void setUnderlineStyle(QTextCharFormat::UnderlineStyle style);
	void setUnderlineColor(const QColor& color);

	inline QColor cursorColor() const
	{ return m_cursor_color; }
	inline QTextCharFormat::UnderlineStyle underlineStyle() const
	{ return m_underline_style; }
	inline QColor underlineColor() const
	{ return m_underline_color; }

private:
	typedef std::list<std::unique_ptr<KTextEditor::MovingRange> > Ranges;

private slots:
	void exclusiveEditStart(KTextEditor::Document*);
	void exclusiveEditEnd(KTextEditor::Document*);

	void textInserted(KTextEditor::Document*, const KTextEditor::Range&);
	void textRemoved(KTextEditor::Document*, const KTextEditor::Range&, const QString&);
	void textBackspace();
	void textDelete();

	void setCursor();
	void removeAll();
	void removeLine();

	void moveNext();
	void movePrev();

	void setActive();

	void setSynchronize();
	void cursorPositionChanged(KTextEditor::View*, const KTextEditor::Cursor&);

	//void debug() const;

protected:
	bool endEditing();
	bool startEditing();
	void insertText(const QString &text);

	template<typename _Functor> inline
	Ranges::reverse_iterator findRangeReverseIterator(const _Functor& func);
	template<typename _Functor> inline
	Ranges::reverse_iterator findRangeReverseIterator(const _Functor& func, const KTextEditor::Cursor& cursor);
	template<typename _Functor> inline
	Ranges::iterator findRangeIterator(const _Functor& func);
	template<typename _Functor> inline
	Ranges::iterator findRangeIterator(const _Functor& func, const KTextEditor::Cursor& cursor);
	template<typename _Functor, typename _Iterator> inline
	_Iterator findRangeIterator(_Iterator it, const _Iterator& end, const _Functor& func, const KTextEditor::Cursor& cursor);

	void removeRange(const Ranges::iterator& it);
	void addRange(KTextEditor::MovingRange* range);
	void connectCurses();
	void disconnectCurses();
	void actionEmptyCurses();
	void actionStartCurses();
	void setEnabled(bool);
	KTextEditor::Cursor advance(const KTextEditor::Cursor&, int length) const;
	KTextEditor::Cursor recoil(const KTextEditor::Cursor&, int length) const;

private:
	void removeTextNext(int length);
	void removeTextPrev(int length);

	inline static const KTextEditor::MovingCursor& _cursor(const Ranges::iterator& it);
	inline static const KTextEditor::MovingCursor& _cursor(Ranges::const_iterator& it);
	inline static int _line(const Ranges::iterator& it);
	inline static int _column(const Ranges::iterator& it);

	inline static KTextEditor::Range rangeMCursor(const KTextEditor::Cursor& cursor);

	KTextEditor::MovingRange* newRange(const KTextEditor::Cursor& cursor) const;

	void setCursor(const KTextEditor::Cursor& cursor);
	void cleanCursor();

	void rangePositionChanged(Ranges::iterator& it, const KTextEditor::Cursor& cursor, KTextEditor::Cursor& cursor_prev);
	void rangePositionChanged(Ranges::iterator& it, int line, KTextEditor::Cursor& cursor_prev);

private:
	KTextEditor::View *m_view;
	KTextEditor::Document *m_document;
	KTextEditor::MovingInterface *m_smart;
	bool m_text_edit;
	bool m_active;
	bool m_synchronize;
	KTextEditor::Cursor m_cursor;
	Ranges m_ranges;
	QColor m_cursor_color;
	QTextCharFormat::UnderlineStyle m_underline_style;
	QColor m_underline_color;
};

#endif
